package server.startup;

import server.Host;
import server.Lifecycle;
import server.Logger;
import server.connector.http.HttpConnector;
import server.core.*;
import server.logger.FileLogger;
import server.logger.SystemOutLogger;
import server.xml.ServerXml;
import server.xml.ServerXmlUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class BootStrap {
    private static boolean debug = false;
    private static boolean start = true;
    private static boolean help = false;

    private static Logger logger = null;
    public static void main(String[] args) {
        initArgs(args);
        if (help) {
            printUsage();
            return;
        }
        if (start) {
            start();
        } else {
            stop();
        }
    }

    private static void initArgs(String[] args) {
        for (String arg : args) {
            if ("debug".equalsIgnoreCase(arg))
                debug = true;
            if ("stop".equalsIgnoreCase(arg))
                start = false;
            if ("help".equalsIgnoreCase(arg))
                help = true;
        }
    }

    private static void printUsage() {
        System.out.println("help:输出帮助信息");
        System.out.println("stop:关闭服务器");
        System.out.println("debug:调试信息输出在显示器");
        System.out.println("\t默认输出到日志文件中");
    }

    private static void start() {
        HttpConnector connector = new HttpConnector();
        Host host = new StandardHost();
        logger = getLogger();
        host.setLogger(logger);

        if (host instanceof Lifecycle)
            ((Lifecycle)host).addLifecycleListener(new HostConfig());
        connector.setContainer(host);
        ServerXml serverXml = null;
        try {
            serverXml = ServerXmlUtil.getServerXml();
            connector.initialize();
            connector.start();
            ((Lifecycle)host).start();
            logger.log("服务器启动成功");
            System.out.println(START_SUCCESS);
        } catch (Throwable e) {
            e.printStackTrace();
            logger.log("\n服务器启动出错");
        }

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                //关闭服务器
                try {
                    connector.stop();
                    ((Lifecycle)host).stop();
                    logger.log("关闭服务器成功");
                    System.out.println(STOP_SUCCESS);
                } catch (Throwable t) {
                    logger.log("关闭服务器出错");
                }
            }
        }));

        try {
            //等待关闭服务器命令
            waitShutdown(serverXml);
        } catch (Throwable t) {
            logger.log("服务器出错");
        }


    }

    private static void waitShutdown(ServerXml serverXml) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(serverXml.getShutdownPort(), 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            logger.log("服务器监听停止端口异常", e);
            System.exit(1);
        }
        String command = serverXml.getShutdownCmd();
        while (true) {
            Socket socket = null;
            InputStream inputStream = null;
            try {
                socket = serverSocket.accept();
                //设置阻塞时间,read阻塞时间超出该值时,会报java.net.SocketTimeoutException异常
                //单位为毫秒
                socket.setSoTimeout(10000);
                inputStream = socket.getInputStream();
            } catch (IOException e) {
                logger.log("服务器监听停止端口异常", e);
                e.printStackTrace();
                System.exit(1);
            }
            int expected = 1024;
            StringBuffer cmd = new StringBuffer();
            while (expected > 0) {
                int ch = -1;
                try {
                    ch = inputStream.read();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (ch == -1)
                    break;
                cmd.append((char)ch);
                expected--;
            }
            try {
                socket.close();
            } catch (IOException e) {
            }

            if (command.equals(cmd.toString()))
                break;
            else
                logger.log("客户端请求关闭服务器,密码错误,错误密码为{" + cmd + "}");
        }
        try {
            serverSocket.close();
        } catch (IOException e) {
        }
    }

    private static void stop() {
        ServerXml serverXml = null;
        try {
            serverXml = ServerXmlUtil.getServerXml();
        } catch (Throwable t) {
            System.out.println("读取配置文件错误");
            t.printStackTrace();
            return;
        }
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            socket = new Socket("127.0.0.1", serverXml.getShutdownPort());
            outputStream = socket.getOutputStream();
            outputStream.write(serverXml.getShutdownCmd().getBytes());
        } catch (IOException e) {
            System.out.println("与服务器通信错误");
            e.printStackTrace();
            return;
        }
        try {
            socket.close();
            System.out.println("命令已发送");
        } catch (Throwable t) {
            System.out.println("关闭连接错误");
            t.printStackTrace();
        }
    }
    private static Logger getLogger() {
        if (debug)
            return new SystemOutLogger();
        else
            return new FileLogger();
    }


    private static final String START_SUCCESS =
            "   _____   ______   _____   __      __  ______   _____         \n" +
            "  / ____| |  ____| |  __ \\  \\ \\    / / |  ____| |  __ \\        \n" +
            " | (___   | |__    | |__) |  \\ \\  / /  | |__    | |__) |       \n" +
            "  \\___ \\  |  __|   |  _  /    \\ \\/ /   |  __|   |  _  /        \n" +
            "  ____) | | |____  | | \\ \\     \\  /    | |____  | | \\ \\        \n" +
            " |_____/  |______| |_|  \\_\\     \\/     |______| |_|  \\_\\       \n" +
            "   _____   _______              _____    _______               \n" +
            "  / ____| |__   __|     /\\     |  __ \\  |__   __|              \n" +
            " | (___      | |       /  \\    | |__) |    | |                 \n" +
            "  \\___ \\     | |      / /\\ \\   |  _  /     | |                 \n" +
            "  ____) |    | |     / ____ \\  | | \\ \\     | |                 \n" +
            " |_____/     |_|    /_/    \\_\\ |_|  \\_\\    |_|                 \n" +
            "   _____   _    _    _____    _____   ______    _____    _____ \n" +
            "  / ____| | |  | |  / ____|  / ____| |  ____|  / ____|  / ____|\n" +
            " | (___   | |  | | | |      | |      | |__    | (___   | (___  \n" +
            "  \\___ \\  | |  | | | |      | |      |  __|    \\___ \\   \\___ \\ \n" +
            "  ____) | | |__| | | |____  | |____  | |____   ____) |  ____) |\n" +
            " |_____/   \\____/   \\_____|  \\_____| |______| |_____/  |_____/ ";
    private static final String STOP_SUCCESS =
            "   _____   ______   _____   __      __  ______   _____         \n" +
            "  / ____| |  ____| |  __ \\  \\ \\    / / |  ____| |  __ \\        \n" +
            " | (___   | |__    | |__) |  \\ \\  / /  | |__    | |__) |       \n" +
            "  \\___ \\  |  __|   |  _  /    \\ \\/ /   |  __|   |  _  /        \n" +
            "  ____) | | |____  | | \\ \\     \\  /    | |____  | | \\ \\        \n" +
            " |_____/  |______| |_|  \\_\\     \\/     |______| |_|  \\_\\       \n" +
            "   _____   _______    ____    _____                            \n" +
            "  / ____| |__   __|  / __ \\  |  __ \\                           \n" +
            " | (___      | |    | |  | | | |__) |                          \n" +
            "  \\___ \\     | |    | |  | | |  ___/                           \n" +
            "  ____) |    | |    | |__| | | |                               \n" +
            " |_____/     |_|     \\____/  |_|                               \n" +
            "   _____   _    _    _____    _____   ______    _____    _____ \n" +
            "  / ____| | |  | |  / ____|  / ____| |  ____|  / ____|  / ____|\n" +
            " | (___   | |  | | | |      | |      | |__    | (___   | (___  \n" +
            "  \\___ \\  | |  | | | |      | |      |  __|    \\___ \\   \\___ \\ \n" +
            "  ____) | | |__| | | |____  | |____  | |____   ____) |  ____) |\n" +
            " |_____/   \\____/   \\_____|  \\_____| |______| |_____/  |_____/ ";

}
